package com.franklin.ideaplugin.easytesting.controllerclient.invoke;

import com.franklin.ideaplugin.easytesting.common.entity.MethodInvokeData;
import com.franklin.ideaplugin.easytesting.common.entity.MethodParameter;
import com.franklin.ideaplugin.easytesting.controllerclient.ClientMethod;
import com.franklin.ideaplugin.easytesting.controllerclient.beans.MethodData;
import com.franklin.ideaplugin.easytesting.controllerclient.beans.RequestData;
import com.franklin.ideaplugin.easytesting.controllerclient.request.IRequestBuilder;
import com.franklin.ideaplugin.easytesting.controllerclient.request.IRequestInvoker;
import com.franklin.ideaplugin.easytesting.common.constants.EasyTestingHeaders;
import lombok.RequiredArgsConstructor;

import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author Ye Junhui
 * @since 2023/6/29
 */
@RequiredArgsConstructor
public class DefaultControllerMethodInvocationHandler implements IControllerMethodInvocationHandler {

    private final IRequestBuilder requestBuilder;
    private final IRequestInvoker requestInvoker;

    private final Map<Method, MethodData> methodMappings;

    @Override
    public Object invoke(Object proxy, Method method, MethodInvokeData invokeData, String targetUrl, Method originMethod, Object[] args) throws Throwable {
        if ("equals".equals(method.getName())) {
            try {
                Object otherHandler =
                        args.length > 0 && args[0] != null ? Proxy.getInvocationHandler(args[0]) : null;
                return equals(otherHandler);
            } catch (IllegalArgumentException e) {
                return false;
            }
        } else if ("hashCode".equals(method.getName())) {
            return hashCode();
        } else if ("toString".equals(method.getName())) {
            return toString();
        }

        ClientMethod clientMethod = ClientMethod.fromMethod(method);
        MethodData methodData = methodMappings.get(originMethod);
        LinkedHashMap<String, MethodParameter> parameterMap = invokeData.getParameterMap();
        String[] paramNames = parameterMap.keySet().toArray(new String[]{});

        Object[] stringArgs = parameterMap.values().stream()
                .map(MethodParameter::getStringValue)
                .toArray();

        LinkedHashMap<String, String> headers = invokeData.getHeaderMap();

        RequestData requestData = this.requestBuilder.buildRequest(methodData,paramNames , stringArgs);
        EasyTestingHeaders.clearEtHeaders(headers);
        headers.forEach(requestData.getHttpHeaders()::add);
        return requestInvoker.invoke(methodData,requestData,targetUrl);
    }
}
